#include "FileScanner.h"

FileScanner::FileScanner(std::string directoryPath) {
    this->_rootPath = directoryPath;
    this->_scan();
}

bool FileScanner::_scan() {
    DIR* dir;                                // 目录文件指针（类似于 FILE 指针，只不过 DIR 指向目录，FILE 指向普通文件）
    dirent* pDirent;                         // 用于保存文件相关属性（比如文件名称，该文件是套接字文件、是软链接文件、是目录、还是普通文件...）
    dir = opendir(this->_rootPath.c_str());  // 打开目录。成功返回指向文件目录的指针，失败返回NULL
    if (NULL == dir) {
        PrintLine("打开目录失败 [%s]", this->_rootPath.c_str());
        return false;
    }
    PrintLine("打开目录成功 [%s]", this->_rootPath.c_str());

    // 为了防止 _scan() 被多次调用导致扫描结果重复保存，每次执行扫描操作前先清空扫描结果
    this->_fileAttrs.clear();
    this->_fileAttrMap.clear();

    // 开始扫描（readdir 每次调用只读取当前目录下，一个文件的文件属性，直至最后一个文件时返回 NULL）
    while (NULL != (pDirent = readdir(dir))) {
        // 如果既不是普通文件、也不是文件目录，则忽略
        // pDirent->d_type & DT_REG 判断是否是普通文件，pDirent->d_type & DT_DIR 判断是否是文件目录
        if (pDirent->d_type != DT_REG && pDirent->d_type != DT_DIR) {
            continue;
        }
        // 如果是 . 或者 .. 目录，同样忽略，使之类似于 Windows 的资源管理器那样
        if (0 == strcmp(pDirent->d_name, ".") || 0 == strcmp(pDirent->d_name, "..")) {
            continue;
        }
        // 如果是普通文件或者文件目录，则保存扫描结果
        this->_fileAttrMap.insert(std::pair<std::string, dirent>(pDirent->d_name, *pDirent));
        this->_fileAttrs.push_back(*pDirent);
    }

    return true;
}

bool FileScanner::_sortFileAttr() {
    std::vector<dirent> dirs, files;  // 保存分类后的目录和文件
    // 遍历扫描结果
    for (int i = 0; i < this->_fileAttrs.size(); i++) {
        // 如果是文件目录
        if (this->_fileAttrs[i].d_type == DT_DIR) {
            dirs.push_back(this->_fileAttrs[i]);
        }
        // 如果是普通文件
        if (this->_fileAttrs[i].d_type == DT_REG) {
            files.push_back(this->_fileAttrs[i]);
        } else {
            PrintLine("当前文件既不是普通文件，也不是文件目录 [%s]", this->_fileAttrs[i].d_name);
            return false;
        }
    }

    // 分类完成后，先清空先前的扫描结果，再把分类后的结果放回去
    this->_fileAttrs.clear();
    this->_fileAttrMap.clear();
    // 保存分类结果
    this->_fileAttrs.insert(this->_fileAttrs.end(), dirs.begin(), dirs.end());
    this->_fileAttrs.insert(this->_fileAttrs.end(), files.begin(), files.end());
    for (int i = 0; i < this->_fileAttrs.size(); i++) {
        this->_fileAttrMap.insert(std::pair<std::string, dirent>(this->_fileAttrs[i].d_name, this->_fileAttrs[i]));
    }

    return true;
}

dirent* FileScanner::_getDirentByIndex(const int index) {
    if (index < 0 || index > this->_fileAttrs.size()) {
        PrintLine("索引下标越界: index [%d] not in [0, %lu]", index, this->_fileAttrs.size());
        return NULL;
    }
    return &this->_fileAttrs[index];
}

std::string FileScanner::_getFileNameByIndex(const int index) {
    dirent* tempDirent = this->_getDirentByIndex(index);
    if (NULL == tempDirent) {
        return "";
    }

    return tempDirent->d_name;
}

unsigned char FileScanner::_getFileTypeByIndex(const int index) {
    dirent* tempDirent = this->_getDirentByIndex(index);
    if (NULL == tempDirent) {
        return 0;
    }

    return tempDirent->d_type;
}

unsigned char FileScanner::_getFileTypeByName(std::string fileName) {
    // 如果文件名不存在
    if (this->_fileAttrMap.find(fileName) == this->_fileAttrMap.end()) {
        PrintLine("文件不存在  [%s]", fileName.c_str());
        return 0;
    }

    return this->_fileAttrMap[fileName].d_type;
}

int FileScanner::_getFileAttrsLength() {
    return this->_fileAttrs.size();
}

FileScanner::~FileScanner() {
    // todo
}
